#!/usr/bin/env -S bun --bun

import { type Serve } from "bun";

export const createServer = async <T>(
  setup = (options: Serve<T>) => options
) => {
  const [, , pubdir = "./public", port = 8080] = Bun.argv;

  type FileInfo = { content: string; type: string };
  const files = new Map<string, FileInfo>();

  const transpiler = new Bun.Transpiler({ loader: "ts" });
  const glob = new Bun.Glob("**");
  for await (const file of glob.scan(pubdir)) {
    const bunFile = Bun.file(`${pubdir}/${file}`);
    let content = await bunFile.text();
    const type = bunFile.type;
    if (
      type.startsWith("text/javascript") ||
      type.startsWith("application/javascript")
    ) {
      content = transpiler.transformSync(content);
    }
    files.set(`/${file}`, { content, type });
  }

  const indexPage = files.get("/index.html");
  const sendFile = (file: FileInfo) =>
    new Response(file.content, {
      headers: {
        "Content-Type": file.type,
      },
    });
  const options = {
    port,
    async fetch(req) {
      const { pathname } = new URL(req.url);
      if ((pathname === "/" || pathname === "/index.html") && indexPage) {
        return sendFile(indexPage);
      }
      const file =
        files.get(pathname) ??
        files.get(`${pathname}.html`) ??
        files.get(`${pathname}.ts`) ??
        files.get(`${pathname}.js`);
      return file ? sendFile(file) : new Response("404", { status: 404 });
    },
  } as Serve<T>;

  return Bun.serve(setup(options));
};

if (import.meta.main) {
  const server = await createServer();
  console.log(`File Server listening at: ${server.url.href}`);
}
